package com.distribute.framework.core.web.session;

import com.distribute.framework.core.web.helper.Utils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import javax.servlet.http.HttpSession;

import com.distribute.framework.core.sql.redis.RedisSupport;


public class RedisSessionHandler implements InvocationHandler {
    
	private HttpSession session = null;
	private static RedisSupport sessionRedis = Utils.getRedis("redis.session");
	private final static int session_max_inactive_interval = 60*60;
	private Set<String> keys = null;

    private RedisSessionHandler(HttpSession httpSession) {
        this.session = httpSession;
    }

	private String getSessionId() {
		String requestSessionId = Utils.or(Utils.getString("TOKEN"), Utils.getString("JSESSIONID")) ;
		if(!Utils.empty(requestSessionId)){
			return requestSessionId;
		}else{
			String sessionid = session.getId();
			return sessionid;
		}
	};

    public static HttpSession getInstance(HttpSession httpSession) {
        InvocationHandler handler = new RedisSessionHandler(httpSession);
        return (HttpSession) Proxy.newProxyInstance(httpSession.getClass().getClassLoader(),new Class[]{HttpSession.class}, handler);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    	if(sessionRedis.initialize){
    		Date last = new Date();
    		if(keys==null){
    			keys = sessionRedis.getMapKeys(getSessionId());
    		}
    		if(keys==null){
    			keys = new HashSet();
    		}
    		try{
		        if ("setAttribute".equals(method.getName())) {
		        	if(args[1]==null)
		        		keys.remove(""+args[0]);
		        	else
		        		keys.add(""+args[0]);
		        	sessionRedis.setMapExpire(getSessionId(), getSessionInterval());
		        	return sessionRedis.setMap(getSessionId(), ""+args[0], args[1]);
		        } else if ("getAttribute".equals(method.getName())) {
		        	if(!keys.contains(""+args[0]))
		        		return null;
		        	sessionRedis.setMapExpire(getSessionId(), getSessionInterval());
		        	Object value = sessionRedis.getMap(getSessionId(), ""+args[0]);
		        	return value;
		        } else if ("removeAttribute".equals(method.getName())) {
		        	keys.remove(""+args[0]);
		        	sessionRedis.setMapExpire(getSessionId(), getSessionInterval());
		        	sessionRedis.deleteMap(getSessionId(), ""+args[0]);
		        	return null;
		        } else if ("getAttributeNames".equals(method.getName())) {
		        	Set<String> keySet = sessionRedis.getMapKeys(getSessionId());
		        	Vector vector = new Vector(); 
		        	for(String key:keySet){
		        		vector.add(key);
		        	}
		        	return vector.elements();
		        } else if ("getId".equals(method.getName())) {
		        	return getSessionId();
		        }
    		}finally{
    			if(sessionRedis.debug){
    				Utils.trace(new Date().getTime()-last.getTime(),method.getName(),Utils.json(args));
    			}
    		}
    	}
    	return method.invoke(session, args);
    }
    
	private int getSessionInterval() {
		return session.getMaxInactiveInterval()>0?session.getMaxInactiveInterval():session_max_inactive_interval;
	}

}